package com.xinlong.shop.core.promotion.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.Week;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xinlong.shop.core.member.entity.MemberActivityIncome;
import com.xinlong.shop.core.member.service.IMemberActivityIncomeService;
import com.xinlong.shop.core.promotion.entity.*;
import com.xinlong.shop.core.promotion.entity.dto.RushPurchaseDetailDTO;
import com.xinlong.shop.core.promotion.mapper.RushPurchaseDetailDTOMapper;
import com.xinlong.shop.core.promotion.mapper.RushPurchaseDetailMapper;
import com.xinlong.shop.core.promotion.service.IRushPurchaseDetailService;
import com.xinlong.shop.framework.core.entity.Member;
import com.xinlong.shop.framework.exception.ServiceException;
import com.xinlong.shop.framework.service.ISysSettingService;
import com.xinlong.shop.framework.util.StringUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 抢购活动明细表 服务实现类
 * </p>
 *
 * @author Sylow
 * @since 2023-02-17
 */
@Service
public class RushPurchaseDetailServiceImpl extends ServiceImpl<RushPurchaseDetailMapper, RushPurchaseDetail> implements IRushPurchaseDetailService {

    private final RushPurchaseDetailDTOMapper rushPurchaseDetailDTOMapper;
    private final RushPurchaseServiceImpl rushPurchaseService;
    private final IMemberActivityIncomeService memberActivityIncomeService;
    private final ISysSettingService sysSettingService;

    public RushPurchaseDetailServiceImpl(RushPurchaseDetailDTOMapper rushPurchaseDetailDTOMapper, RushPurchaseServiceImpl rushPurchaseService, IMemberActivityIncomeService memberActivityIncomeService, ISysSettingService sysSettingService) {
        this.rushPurchaseDetailDTOMapper = rushPurchaseDetailDTOMapper;
        this.rushPurchaseService = rushPurchaseService;
        this.memberActivityIncomeService = memberActivityIncomeService;
        this.sysSettingService = sysSettingService;
    }

    @Override
    public void update(RushPurchaseDetail rushPurchaseDetail, Integer id) {
        UpdateWrapper<RushPurchaseDetail> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("id", id);
        this.update(rushPurchaseDetail, updateWrapper);
    }

    @Override
    public void delete(Integer id) {
        UpdateWrapper<RushPurchaseDetail> deleteWrapper = new UpdateWrapper<>();
        deleteWrapper.eq("id", id);
        this.remove(deleteWrapper);
    }

    @Override
    public List<RushPurchaseDetail> listByRushPurchaseId(Integer rushPurchaseId) {
        QueryWrapper<RushPurchaseDetail> query = new QueryWrapper<>();
        query.eq("rush_purchase_id", rushPurchaseId);
        return this.list(query);
    }

    @Override
    public RushPurchaseDetailDTO findDTOById(Integer rushPurchaseDetailId) {
        return this.rushPurchaseDetailDTOMapper.findById(rushPurchaseDetailId);
    }

    @Override
    public IPage<RushPurchaseDetailDTO> page(IPage<RushPurchaseDetailDTO> page, Integer rushPurchaseId, Integer min, Integer max, Integer isVip) {
        return this.rushPurchaseDetailDTOMapper.findByPage(page, rushPurchaseId, min, max, isVip);
    }

    @Override
    public IPage<RushPurchaseDetail> findPageByParam(IPage<RushPurchaseDetail> page, RushPurchaseDetailQueryParam rushPurchaseDetailQueryParam) {
        QueryWrapper<RushPurchaseDetail> query = new QueryWrapper<>();
        query.eq(rushPurchaseDetailQueryParam.getRushPurchaseId() != null, "rush_purchase_id", rushPurchaseDetailQueryParam.getRushPurchaseId());
        query.like(StrUtil.isNotBlank(rushPurchaseDetailQueryParam.getBuyerName()), "buyer_name", rushPurchaseDetailQueryParam.getBuyerName());
        query.like(StrUtil.isNotBlank(rushPurchaseDetailQueryParam.getBuyerMobile()), "buyer_mobile", rushPurchaseDetailQueryParam.getBuyerMobile());
        query.like(StrUtil.isNotBlank(rushPurchaseDetailQueryParam.getSellerName()), "seller_name", rushPurchaseDetailQueryParam.getSellerName());
        query.like(StrUtil.isNotBlank(rushPurchaseDetailQueryParam.getSellerMobile()), "seller_mobile", rushPurchaseDetailQueryParam.getSellerMobile());
        query.like(StrUtil.isNotBlank(rushPurchaseDetailQueryParam.getGoodsName()), "goods_name", rushPurchaseDetailQueryParam.getGoodsName());
        query.like(StrUtil.isNotBlank(rushPurchaseDetailQueryParam.getOrderSn()), "order_sn", rushPurchaseDetailQueryParam.getOrderSn());
        query.eq(rushPurchaseDetailQueryParam.getStatus() != null, "status", rushPurchaseDetailQueryParam.getStatus());


        query.eq(rushPurchaseDetailQueryParam.getIsPickUp() != null, "is_pick_up", rushPurchaseDetailQueryParam.getIsPickUp());
        if (rushPurchaseDetailQueryParam.getBuyTime() != null && rushPurchaseDetailQueryParam.getBuyTime().length == 2) {
            // 下单时间区间(开始时间,结束时间
            query.between("buy_time", rushPurchaseDetailQueryParam.getBuyTime()[0] / 1000, rushPurchaseDetailQueryParam.getBuyTime()[1] / 1000);
        }
        // 不显示的状态
        if (rushPurchaseDetailQueryParam.getFilterStatus() != null) {
            query.ne("status", rushPurchaseDetailQueryParam.getFilterStatus());
        }

        // 如果按照状态筛选了 就不显示已经提货的
        if (rushPurchaseDetailQueryParam.getStatus() != null && rushPurchaseDetailQueryParam.getStatus() == DetailStatusEnum.CONFIRM.getCode()) {
            query.eq("is_pick_up", 0);
        }
        // 排序
        if (rushPurchaseDetailQueryParam.getSortType().equals("asc")) {
            query.orderByAsc(rushPurchaseDetailQueryParam.getSortName());
        } else {
            query.orderByDesc(rushPurchaseDetailQueryParam.getSortName());
        }
        return this.page(page, query);
    }

    @Override
    public synchronized String buy(Integer rushPurchaseDetailId, Member member) {

        RushPurchaseDetailDTO detail = this.findDTOById(rushPurchaseDetailId);
        Long nowTime = DateUtil.date().getTime() / 1000;

        // 判断是否有预订
        if (detail.getBookingMemberId() != null && detail.getBookingMemberId().intValue() != 0) {
            if (detail.getBookingMemberId().intValue() != member.getId().intValue()){
                return "已被其他用户预订";
            }
        }

        // 非未采购状态
        if (detail.getStatus().intValue() != 0) {
            return "已被其他用户抢购";
        }
        // 活动已结束
        if (nowTime > detail.getEndTime()) {
            return "活动已结束";
        }
        // 会员角色暂时用id 1普通会员 2优先抢购会员 3 无限抢购会员 4团长
        // 如果活动时间之前vip 特权判断
        if (nowTime < detail.getStartTime()) {
            // 如果是普通会员（没有特权）  这里暂时用id，后期优化
            if (member.getGradeId().intValue() == 1) {
                return "活动未开始";
            } else {
                // 如果是vip会员 提前30秒抢
                if (nowTime < detail.getStartTime() - 30) {
                    return "活动未开始";
                }
            }
        }

        // 限购 不是高级会员和购车特权都有限制
        if (member.getGradeId().intValue() != 3 && member.getGradeId().intValue() != 5) {

            QueryWrapper<RushPurchaseDetail> query = new QueryWrapper<>();
            query.eq("rush_purchase_id", detail.getRushPurchaseId());
            query.eq("buyer_id", member.getId());
            long orderNum = this.count(query);  //抢购订单数
            // 优先vip 提前抢购的时间30秒内 限制1块
            if(detail.getStartTime() > nowTime && detail.getStartTime() - nowTime <= 30 && member.getGradeId().intValue() != 6){
                if (orderNum >= 1) {
                    return "提前抢购每人限购1件";
                }
            } else {
                if (member.getGradeId().intValue() == 4 ) {
                    if (orderNum >= 3) {
                        return "每人限购3件";
                    }
                }else if (member.getGradeId().intValue() == 6) {
                    if (orderNum >= 6) {
                        return "每人限购6件";
                    }
                }
                else {
                    if (orderNum >= 2) {
                        return "每人限购2件";
                    }
                }

            }
        }

        UpdateWrapper<RushPurchaseDetail> update = new UpdateWrapper<>();
        update.set("buyer_id", member.getId());
        update.set("buyer_name", member.getNickname());
        update.set("buyer_mobile", member.getMobile());
        update.set("buy_time", DateUtil.date().getTime() / 1000);
        update.set("status", DetailStatusEnum.BUY.getCode());
        update.eq("id", rushPurchaseDetailId);
        boolean result = this.update(update);
        String resultStr = "";
        if (result) {
            // 成功标识
            resultStr = "success";
        } else {
            //
            resultStr = "系统错误";
        }
        return resultStr;
    }

    @Override
    public IPage<RushPurchaseDetailDTO> findBuyerOrder(IPage<RushPurchaseDetailDTO> page, Integer memberId, Integer status) {

        return this.rushPurchaseDetailDTOMapper.findPageByBuyer(page, memberId, status);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void uploadProof(Integer id, Integer buyerId, String imgUrl) {
        UpdateWrapper<RushPurchaseDetail> update = new UpdateWrapper<>();
        update.set("pay_proof", imgUrl);
        update.set("status", DetailStatusEnum.PAY.getCode());
        update.eq("buyer_id", buyerId);
        update.eq("id", id);
        boolean result = this.update(update);
        if (result) {
            MemberActivityIncome memberActivityIncome = memberActivityIncomeService.findByRushPurchaseDetailId(id);
            if (memberActivityIncome == null) {
                // 计算利润 插入到会员收益表 销售价-原价-服务费=利润
                // 这里不用之前上架实际的付款数据是因为  费用会员可能缴纳错误，运营会让会员补交，所以再按照系统配置算一遍
                RushPurchaseDetail rpd = this.getById(id);
                Map<String, BigDecimal> incomeInfo = getIncomeInfo(rpd);
                BigDecimal servicePrice = incomeInfo.get("servicePrice");
                BigDecimal profit = incomeInfo.get("profit");

                this.memberActivityIncomeService.addActivityIncome(rpd.getSellerId(), rpd.getOriginalPrice(),
                        rpd.getPrice(), servicePrice, profit, id, rpd.getActivityId());
            }
        }


    }


    @Override
    public IPage<RushPurchaseDetailDTO> findSellerOrder(IPage<RushPurchaseDetailDTO> page, Integer memberId, Integer status) {
        return this.rushPurchaseDetailDTOMapper.findPageBySeller(page, memberId, status);
    }

    @Override
    public void confirmReceipt(Integer id, Integer sellerId) {
        UpdateWrapper<RushPurchaseDetail> update = new UpdateWrapper<>();
        update.set("status", DetailStatusEnum.CONFIRM.getCode());
        update.eq("seller_id", sellerId);
        update.eq("id", id);
        this.update(update);

    }

    @Override
    public void confirmReceipt(Integer id) {
        UpdateWrapper<RushPurchaseDetail> update = new UpdateWrapper<>();
        update.set("status", DetailStatusEnum.CONFIRM.getCode());
        update.eq("id", id);
        this.update(update);
    }

    @Override
    public void pickUp(Integer id, Integer buyerId) {
        UpdateWrapper<RushPurchaseDetail> update = new UpdateWrapper<>();
        update.set("is_pick_up", 1);
        update.eq("buyer_id", buyerId);
        update.eq("id", id);
        this.update(update);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer putSale(Integer id, PutSaleOrder putSaleOrder) {

        RushPurchaseDetail rpd = this.getById(id);
        // 得到上一场活动详情
        RushPurchase lastRp = rushPurchaseService.getById(rpd.getRushPurchaseId());

        // 查看有没有生成好活动  第一个人上架才会生成
        RushPurchase rushPurchase = rushPurchaseService.findByLastId(lastRp.getId());
        if (rushPurchase == null) {

            rushPurchase = getNextRushPurchase(lastRp);
            // 保存
            rushPurchaseService.save(rushPurchase);
        }

        RushPurchaseDetail nextRpd = this.find(rushPurchase.getActivityId(), rpd.getGoodsId());

        // 如果下一场已经有了  就不新增了
        if (nextRpd == null) {

            // 组装新活动明细
            nextRpd = new RushPurchaseDetail();
            nextRpd.setCreateTime(DateUtil.currentSeconds());
            nextRpd.setRushPurchaseId(rushPurchase.getId());
            nextRpd.setActivityId(rushPurchase.getActivityId());
            nextRpd.setIsVip(rpd.getIsVip());
            // 生成订单号 这里要改成统一的地方
            String orderSn = "P" + rushPurchase.getActivityId() + StringUtil.random(10000) + rpd.getGoodsId();
            nextRpd.setOrderSn(orderSn);
            nextRpd.setGoodsId(rpd.getGoodsId());
            nextRpd.setGoodsName(rpd.getGoodsName());
            nextRpd.setSellerId(rpd.getBuyerId());
            nextRpd.setSellerName(rpd.getBuyerName());
            nextRpd.setSellerMobile(rpd.getBuyerMobile());
            nextRpd.setOriginalPrice(rpd.getPrice());
            nextRpd.setPrice(putSaleOrder.getNewPrice());

            // 保存新的活动明细
            this.save(nextRpd);
        }
        // 把当前场次改为已上架
        rpd.setStatus(DetailStatusEnum.PUT_SALE.getCode());
        this.update(rpd, id);

        // 返回新活动场次id
        return nextRpd.getId();
    }

    @Override
    public RushPurchaseDetail find(String activityId, Integer goodsId) {
        QueryWrapper<RushPurchaseDetail> query = new QueryWrapper<>();
        query.eq("activity_id", activityId);
        query.eq("goods_id", goodsId);
        return this.getOne(query);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancelOrder(Integer id) {
        RushPurchaseDetail rpd = this.getById(id);
        if (rpd.getStatus().intValue() != DetailStatusEnum.BUY.getCode()) {
            throw new ServiceException("订单状态不正确");
        }
        UpdateWrapper<RushPurchaseDetail> update = new UpdateWrapper<>();
        update.set("status", DetailStatusEnum.CANCEL.getCode());
        update.eq("id", id);
        boolean result = this.update(update);
        if (result) {
            RushPurchaseDetail newRpd = new RushPurchaseDetail();
            newRpd.setActivityId(rpd.getActivityId());
            newRpd.setRushPurchaseId(rpd.getRushPurchaseId());
            newRpd.setPrice(rpd.getPrice());
            newRpd.setOriginalPrice(rpd.getOriginalPrice());
            newRpd.setGoodsId(rpd.getGoodsId());
            newRpd.setGoodsName(rpd.getGoodsName());
            newRpd.setSellerName(rpd.getSellerName());
            newRpd.setSellerId(rpd.getSellerId());
            newRpd.setSellerMobile(rpd.getSellerMobile());
            newRpd.setStatus(DetailStatusEnum.NOT_BUY.getCode());
            newRpd.setCreateTime(rpd.getCreateTime());
            newRpd.setOrderSn("P" + newRpd.getActivityId() + StringUtil.random(10000) + newRpd.getGoodsId());
            boolean resultSave = this.save(newRpd);
            if (!resultSave) {
                throw new ServiceException("取消订单失败");
            }
        }
    }

    @Override
    public BigDecimal getExpectIncome(Integer memberId) {
        QueryWrapper<RushPurchaseDetail> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("seller_id", memberId);
        queryWrapper.eq("status", DetailStatusEnum.NOT_BUY);
        List<RushPurchaseDetail> list = this.list(queryWrapper);
        BigDecimal expectIncome = BigDecimal.ZERO;
        for (RushPurchaseDetail rpd : list) {
            Map<String, BigDecimal> incomeInfo = getIncomeInfo(rpd);
            BigDecimal profit = incomeInfo.get("profit");
            expectIncome = expectIncome.add(profit);
        }

        return expectIncome;
    }

    @Override
    public long countByStatus(Integer status) {
        QueryWrapper<RushPurchaseDetail> queryWrapper = new QueryWrapper<>();
        if (status != null) {
            queryWrapper.eq("status", status);
            queryWrapper.eq("is_pick_up", 0);
        } else {
            // 等于null 就是查询除了未购买的所有
            queryWrapper.ne("status", DetailStatusEnum.NOT_BUY.getCode());
        }

        return this.baseMapper.selectCount(queryWrapper);
    }

    @Override
    public BigDecimal getTotleByRushPurchaseId(Integer rushPurchaseId) {
        QueryWrapper<RushPurchaseDetail> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("rush_purchase_id", rushPurchaseId);
        queryWrapper.ne("status", DetailStatusEnum.CANCEL.getCode());
        queryWrapper.select("sum(price) as price");
        RushPurchaseDetail rushPurchaseDetail = this.getOne(queryWrapper);
        if (rushPurchaseDetail == null) {
            return BigDecimal.ZERO;
        }
        return rushPurchaseDetail.getPrice();
    }

    @Override
    public int getBuyerOrderCount(Integer memberId, Integer rushPurchaseId) {
        QueryWrapper<RushPurchaseDetail> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("rush_purchase_id", rushPurchaseId);
        queryWrapper.eq("buyer_id", memberId);

        return (int) this.count(queryWrapper);
    }

    @Override
    public List<RushPurchaseDetail> findBuyerOrder(Integer memberId, String activityId) {
        QueryWrapper<RushPurchaseDetail> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("activity_id", activityId);
        queryWrapper.eq("buyer_id", memberId);
        queryWrapper.eq("status", DetailStatusEnum.CONFIRM.getCode());
        return this.list(queryWrapper);
    }

    @Override
    public boolean updateVip(Integer id, Integer isVip) {
        UpdateWrapper<RushPurchaseDetail> updateWrapper = new UpdateWrapper<>();
        updateWrapper.set("is_vip", isVip);
        updateWrapper.eq("id", id);
        return this.update(updateWrapper);
    }

    @Override
    public void setBookingMember(Integer id, Integer memberId) {
        UpdateWrapper<RushPurchaseDetail> updateWrapper = new UpdateWrapper<>();
        updateWrapper.set("booking_member_id", memberId);
        updateWrapper.eq("id", id);
        this.update(updateWrapper);
    }

    /**
     * 获取收益信息（服务费、利润）
     * @param rpd
     * @return
     */
    private Map<String, BigDecimal> getIncomeInfo(RushPurchaseDetail rpd) {
        // 获取系统配置
        Map<String, Object> setting = sysSettingService.getSetting();
        Double putSalePrice = (Double) setting.get("putSalePrice");
        // 配置中是整数 需要除以100
        Double divisor = 100D;
        putSalePrice = NumberUtil.div(putSalePrice, divisor, 3);

        // 服务费=旧价格*百分比
        BigDecimal servicePrice = NumberUtil.mul(rpd.getOriginalPrice(), putSalePrice);
        servicePrice = servicePrice.setScale(2, BigDecimal.ROUND_HALF_UP);

        BigDecimal profit = NumberUtil.sub(NumberUtil.sub(rpd.getPrice(), rpd.getOriginalPrice()), servicePrice);
        Map<String, BigDecimal> result = new HashMap<>();
        result.put("servicePrice", servicePrice);
        result.put("profit", profit);
        return result;
    }

    /**
     * 得到下一场次活动
     * @param lastRp 上一场活动
     * @return
     */
    private RushPurchase getNextRushPurchase(RushPurchase lastRp) {
        String activityId = lastRp.getActivityId();


        int offset = 1;
        // 如果今天是周五 那么间隔时间是3天 就是下周一 以此类推
        if (Week.FRIDAY == DateUtil.dayOfWeekEnum(DateUtil.date())) {
            offset = 3;
        }
        if (Week.SATURDAY == DateUtil.dayOfWeekEnum(DateUtil.date())) {
            offset = 2;
        }
        if (Week.SUNDAY == DateUtil.dayOfWeekEnum(DateUtil.date())) {
            offset = 1;
        }


        // 得到新的活动时间
        Long newStartTime = DateUtil.offsetDay(DateUtil.date(lastRp.getStartTime() * 1000L), offset).getTime() / 1000L;
        Long newEndTime = DateUtil.offsetDay(DateUtil.date(lastRp.getEndTime() * 1000L), offset).getTime() / 1000L;
        Long newCreateTime = DateUtil.currentSeconds();

        // 得到新的活动场次id  规则是日期+序号  例如 2023033001
        String dateStr = DateUtil.format(DateUtil.date(newStartTime * 1000L),"yyyyMMdd");
        String number = activityId.substring(8);  // 得到序号
        activityId = dateStr + number;

        RushPurchase nextRushPurchase = new RushPurchase();
        nextRushPurchase.setLastId(lastRp.getId());
        nextRushPurchase.setActivityId(activityId);
        nextRushPurchase.setActivityName(lastRp.getActivityName());
        nextRushPurchase.setStartTime(newStartTime);
        nextRushPurchase.setEndTime(newEndTime);
        nextRushPurchase.setCreateTime(newCreateTime);
        nextRushPurchase.setIsVip(lastRp.getIsVip());

        return nextRushPurchase;
    }

    public static void main(String[] args) {
        String begin = DateUtil.format(DateUtil.tomorrow(),"yyyyMMdd");
        String str = "2022070801";
        System.out.println(begin + str.substring(8, str.length()));

        System.out.println(DateUtil.offsetDay(DateUtil.date(1680079543000L), 1).getTime());
        System.out.println(DateUtil.dayOfWeekEnum(DateUtil.offsetDay(DateUtil.date(1680165943000L), 1)));
    }

}
